﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.Unity;
using Wyn.PMS.Common.SecurityControl;
using Wyn.PMS.Common.Utils;
using Wyn.PMS.Entity.Entities;
using Wyn.PMS.Entity.IDataAccess;
using Wyn.PMS.Entity.DataAccess;

namespace Wyn.PMS.Common.NightAudit
{
    public class ResvHelper
    {
        private readonly IUnityContainer container = UnityContainerService.GetContainer();

        private const string MYSTERY_ROOM = "0000";

        public void ProcessNoShow(string hotelId,Reservation resv,string orderId,string roomTypeId,string employeeId,string shiftId,string memo)
        {
            IAccountRepository accountRepository = container.Resolve<IAccountRepository>();

            IOrderRepository orderRepository = container.Resolve<IOrderRepository>();

            IReserveRepository reserveRepository = container.Resolve<IReserveRepository>();

            DateTime todayBizDay = BizDay.Get(hotelId);

            string resvId = resv.ResvID;

            NoShowProcess noshowProcess = new NoShowProcess();

            if (resv.Status != EnumHelper.GetCode(ReserveStatus.R))
            {
                throw new ArgumentException(string.Format("订单当前状态为：{0},不能做NOSHOW", CodeHelper.GetName<ReserveStatus>(resv.Status)));
            }

            resv= noshowProcess.UpdateNosShowReservation(new List<Reservation> {resv},employeeId).FirstOrDefault();

            IList<RoomOccupy> noShowOccupies = noshowProcess.UpdateNoShowOccupies(resv.RoomOccupy, todayBizDay, employeeId);

            IList<Order> noShowOrders = noshowProcess.UpdateNoShowOrders(resv.Order,employeeId);

            var checkInOrder = noShowOrders.FirstOrDefault(o => o.OrderID == orderId);
            
            if(noShowOrders!=null&&noShowOrders.Any())
            {
                noShowOrders = noShowOrders.Where(o => o.OrderID != orderId).ToList();
            }

            resv.Memo += memo;

            string asI = EnumHelper.GetCode(AccountStatus.I);

            string art_RV = EnumHelper.GetCode(AccountRootType.RV);

            IList<Account> accounts = accountRepository.BatchFind(hotelId, a => a.HotelID == hotelId && a.CreateOrderID == resvId && a.Status == asI && a.AccountRootType == art_RV);
            
            Order order = null;

            AccountRoot accountRoot = null;

            Account newAccount = null;

            string checkId = BillGenerator.CreateID(resv.HotelID, GlobalConst.CHECK_ID_PREFIX);

            if (accounts != null && accounts.Count > 0)
            {
                decimal credit = accounts.Where(a => a.Status == EnumHelper.GetCode(AccountStatus.I) && a.LedgerType == AccountType.C).Sum(o => o.Balance);

                decimal debit = accounts.Where(a => a.Status == EnumHelper.GetCode(AccountStatus.I) && a.LedgerType == AccountType.D).Sum(o => o.Balance);

                if (credit - debit < 0)
                {
                    throw new Exception("欠费状态不能Noshow，请及时补交预订定金");
                }

                //大于零需进行NOSHOW账处理
                if (credit - debit > 0)
                {
                    order = BuildNoShowOrder(resv, checkInOrder, todayBizDay, employeeId, orderRepository);

                    accountRoot = BuildAccountRoot(order);

                    newAccount = BuildAccount(order, credit - debit, todayBizDay, checkId, shiftId, memo);

                    accounts = BuildAccounts(accounts, order, checkId, shiftId);

                    memo+=string.Format("NOSHOW客房收入：{0}元。", credit - debit);

                    resv.Memo += memo;
                }

                accounts = UpdateAcconts(accounts, employeeId, checkId);
            }

            reserveRepository.NoshowReservation(hotelId, new List<Reservation>{ resv }, noShowOrders, noShowOccupies, accountRoot, accounts, newAccount,order);

            string msg = "Noshow订单"+ resvId+ memo;
            
            OperateLog.InfoLog(new LogMessage(LogCategory.ResvNoShow,employeeId,resvId,"R",memo,true,hotelId,msg));

        }
        /// <summary>
        /// 街客帐入房费
        /// </summary>
        /// <param name="hotelId"></param>
        /// <param name="accounts"></param>
        /// <param name="roomTypeId"></param>
        /// <param name="employeeId"></param>
        /// <param name="shiftId"></param>
        /// <param name="memo"></param>
        public void FullDiurnalRentOrder(string hotelId, IList<Account> accounts,List<CheckBill> checkBills,  string roomTypeId, string employeeId, string shiftId, string memo)
        {
            if (string.IsNullOrWhiteSpace(hotelId) || string.IsNullOrWhiteSpace(roomTypeId))
            {
                throw new Exception("无法对未指定酒店和房型收取全日租街客账");
            }
            IAccountRepository accountRepository = container.Resolve<IAccountRepository>();
            if (accounts != null && accounts.Count > 0)
            {
                decimal price = accounts.FirstOrDefault().Balance;
                //生成Order单
                Order orderAdd = BuildDiurnalRentOrder(hotelId, price, roomTypeId, employeeId, memo);
                //生成AccountRoot 
                AccountRoot accountRootAdd = BuildAccountRoot(orderAdd);
                foreach (Account account in accounts)
                {
                    account.AccountRootID = accountRootAdd.AccountRootID;
                }
                //直接调服务搞了
                accountRepository.InsertStreetRoomAccount(hotelId, orderAdd, accountRootAdd, accounts, checkBills);
            }
        }

        private AccountRoot BuildAccountRoot(Order order)
        {
            AccountRoot accountRoot = new AccountRoot()
            {
                AccountName = order.GuestName,
                AccountRootID = order.OrderID,
                AccountRootType = EnumHelper.GetCode(AccountRootType.RA),
                CreateDateTime = DateTime.Now,
                EmployeeID = order.EmployeeID,
                GroupID = order.GroupID,
                HotelID = order.HotelID,
                ModifiedTime = DateTime.Now,
                CloseBizDay=order.CheckOutBizDay,
                Status = EnumHelper.GetCode(AccountStatus.O)
            };
            return accountRoot;
        }

        /// <summary>
        /// 有账要处理NOSHOW到房账
        /// </summary>
        /// <returns></returns>
        private IList<Account> BuildAccounts(IList<Account> accounts,Order order,string checkId,string shiftId)
        {
            foreach (var item in accounts)
            {
                item.Status = EnumHelper.GetCode(AccountStatus.O);
                item.AccountRootType = EnumHelper.GetCode(AccountRootType.RA);
                item.CheckID = checkId;
                item.CheckInType = order.CheckInType;
                item.AccountRootID = order.OrderID;
                item.EmployeeID = order.EmployeeID;
                item.LatestRoomNo = order.RoomNo;
                item.ModifiedTime = DateTime.Now;
                item.ShiftID = shiftId;
            }

            return accounts;
        }

        /// <summary>
        /// 账单已平 无需录入房账
        /// </summary>
        /// <returns></returns>
        private Account BuildAccount(Order order, decimal price, DateTime bizDay, string checkId, string shiftId, string memo)
        {
            var account = new Account
            {
                AccountRootID = order.OrderID,
                AccountID = BillGenerator.CreateID(order.HotelID, AccountType.D),
                AccountRootType = EnumHelper.GetCode(AccountRootType.RA),
                ActualMoney = price,
                Balance = price,
                BizDay = bizDay,
                CheckID = checkId,
                CheckInType = order.CheckInType,
                CreateEmployeeId = order.EmployeeID,
                CreateOrderID = order.OrderID,
                CreateTime = DateTime.Now,
                EmployeeID = order.EmployeeID,
                HotelID = order.HotelID,
                LatestRoomNo = order.RoomNo,
                LedgerCode = LedgerCode.标准房租,
                LedgerParentCode = LedgerCode.客房收入,
                LedgerType = AccountType.D,
                ModifiedTime = DateTime.Now,
                Note = memo,
                NoteFlag = AccountNote.结帐退房,
                PaidAccountRootID = order.OrderID,
                PaidDate = DateTime.Now,
                PaidOperatorID = order.EmployeeID,
                Status = EnumHelper.GetCode(AccountStatus.O),
                ResvID = order.ResvID,
                ShiftID = shiftId,
            };

            return account;
        }

        private IList<Account> UpdateAcconts(IList<Account> accounts,string employeeId,string checkId)
        {
            foreach (var item in accounts)
            {
                item.EmployeeID = employeeId;
                item.NoteFlag = AccountNote.结帐退房;
                item.CheckID = checkId;
                item.Status = EnumHelper.GetCode(AccountStatus.O);
            }
            return accounts;
        }

        private IList<CheckBill> BuildCheckBills()
        {
            return null;
        }

        private Order BuildNoShowOrder(Reservation resv, Order order, DateTime todayBizDay, string employeeId, IOrderRepository orderRepository)
        {
            if (order == null)
            {
                throw new ArgumentNullException("必须排房填写入住人信息才能NOSHOW");
            }

            order.ActivityCode = resv.ActivityCode;
            order.ChannelID = resv.ChannelID;
            order.CheckInType = resv.CheckInType;
            order.CheckinTime = DateTime.Now.AddMinutes(-1);
            order.CheckInBizDay = todayBizDay;
            order.CheckOutTime = resv.EndDate;
            order.CheckOutBizDay = todayBizDay;
            order.Country = GlobalConst.COUNTRY_中国;
            order.EmployeeID = employeeId;
            order.GroupID = resv.GuestSourceType == EnumHelper.GetCode(GuestSourceType.GP)
                               ? resv.ResvID
                               : string.Empty;
            order.GroupName = resv.GroupCompanyName;
            order.GroupType = resv.GroupType;
            order.GuestSourceType = resv.GuestSourceType;
            order.LongPacketNo = resv.LongPacketNo;
            order.MemberNo = resv.MemberNo;
            order.MemberType = resv.MemberType;
            order.ModifiedTime = DateTime.Now;
            order.Note = resv.Memo;
            order.ResvID = resv.ResvID;
            order.SalesID = resv.SalesID;
            order.Status = EnumHelper.GetCode(OrderStatus.O);
            order.Telephone = resv.Tel;
            return order;
        }

        private Order BuildDiurnalRentOrder(string hotelId,decimal price, string roomTypeId, string employeeId,string memo)
        {
            //DateTime todayBizDay = BizDay.Get(hotelId);

            DateTime defaultDate = new DateTime(1984, 11, 09);

            string orderId = LicenceGenerator.GetNo(hotelId, LicenceType.RcpnOrder);

            var order = new Order()
                            {
                                OrderID = orderId,
                                ArrivalDate = defaultDate,
                                DepartureDate = defaultDate.AddMinutes(1),
                                CheckinTime = defaultDate,
                                CheckInBizDay = defaultDate,
                                CheckOutTime = defaultDate.AddMinutes(1),
                                CheckOutBizDay = defaultDate,
                                HotelID = hotelId,
                                PriceDetail = new List<PriceDetail>
                                                  {
                                                      new PriceDetail
                                                          {
                                                              BizDay = defaultDate,
                                                              HotelID = hotelId,
                                                              OrderID = orderId,
                                                              NormalPrice = price,
                                                              Price = price
                                                          }
                                                  },
                                RoomTypeID = roomTypeId,
                                RoomNo = MYSTERY_ROOM,
                                ChannelID = 1,
                                CheckInType = EnumHelper.GetCode(CheckInType.NS),
                                GuestSourceType = EnumHelper.GetCode(GuestSourceType.WI)
                            };
            order.Country = GlobalConst.COUNTRY_中国;
            order.Gender = (int) BaseCode.Gender.Male;
            order.EmployeeID = employeeId;
            order.GuestName = "现付账房租收款";
            order.HotelID = hotelId;
            order.ModifiedTime = DateTime.Now;
            order.Note = memo;
            order.Status = EnumHelper.GetCode(OrderStatus.O);
            return order;

        }

    }
}
